﻿/*
 * Copyright 2014 Francois Karman
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

using Quartz.Impl.Matchers;
using Quartz.WebManager.Model;
using System;
using System.Collections.Generic;
using System.Linq;

namespace Quartz.WebManager.Logic
{
    public static class TriggerManager
    {
        public static IEnumerable<Trigger> RetrieveAll()
        {
            return Factory.GetScheduler().GetTriggerKeys(GroupMatcher<TriggerKey>.AnyGroup()).Select(k => RetrieveOne(k)).ToArray();
        }

        public static IEnumerable<Trigger> RetrieveForJob(JobKey key)
        {
            return Factory.GetScheduler().GetTriggersOfJob(key).Select(t => Convert(t)).ToArray();
        }

        public static Trigger RetrieveOne(TriggerKey key)
        {
            return Convert(Factory.GetScheduler().GetTrigger(key));
        }

        /// <summary>
        /// Saves a trigger.
        /// </summary>
        /// <param name="model">The detail about the trigger.</param>
        /// <param name="replace">A value indicating whether an existing trigger should be replaced.</param>
        /// <returns>The key of the created/updated trigger.</returns>
        public static TriggerKey SaveOne(Trigger model, bool replace = false)
        {
            TriggerBuilder builder = TriggerBuilder.Create()
                .WithIdentity(model.Name, model.Group)
                .ForJob(model.JobName, model.JobGroup)
                .WithDescription(model.Description)
                .WithPriority(model.Priority)
                .WithCronSchedule(model.CronExpression, action => action.WithMisfireHandling(model.MisfireInstruction));

            if (model.StartTime.HasValue)
            {
                builder.StartAt(model.StartTime.Value);
            }
            if (model.EndTime.HasValue)
            {
                builder.EndAt(model.EndTime.Value);
            }

            if (replace)
            {
                Factory.GetScheduler().UnscheduleJob(new TriggerKey(model.Name, model.Group));
            }

            ITrigger trigger = builder.Build();
            Factory.GetScheduler().ScheduleJob(trigger);
            return trigger.Key;
        }

        public static void RemoveOne(TriggerKey key)
        {
            Factory.GetScheduler().UnscheduleJob(key);
        }

        private static Trigger Convert(ITrigger trigger)
        {
            DateTime? endTime = null;
            if (trigger.EndTimeUtc.HasValue)
            {
                endTime = trigger.EndTimeUtc.Value.LocalDateTime;
            }

            return new Trigger()
            {
                Group = trigger.Key.Group,
                Name = trigger.Key.Name,
                JobGroup = trigger.JobKey.Group,
                JobName = trigger.JobKey.Name,
                Description = trigger.Description,
                StartTime = trigger.StartTimeUtc.LocalDateTime,
                EndTime = endTime,
                Priority = trigger.Priority,
                MisfireInstruction = trigger.MisfireInstruction,
                CronExpression = ((ICronTrigger)trigger).CronExpressionString,
            };
        }
    }
}
